/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

// a normalized rectangle is computed once and sent as a uniform; each particle just needs to add it's position
// (probably not relevant with point sprites though)

#include "fxVSIncludes.fx"

struct VS_PARTICLE
{
	float3 Origin : ORIGIN;
	float4 ColorLo : COLORLO;
	float4 ColorHi : COLORHI;
	float ColorTime : COLORTIME;
};


struct GS_PARTICLE
{
	float3 Origin : ORIGIN;
	float HackScale : HACKSCALE;
	float4 Color : COLOR;
};


struct PS_PARTICLE
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
	float2 Offsets : TEXCOORD0;
};


#ifdef VERTEXSHADER
GS_PARTICLE ParticleCommonVS (VS_PARTICLE vs_in)
{
	GS_PARTICLE vs_out;

	vs_out.Origin = vs_in.Origin;
	vs_out.HackScale = 1.0f + dot (vs_out.Origin - EyePositionWorld, forwardVec) * 0.002f;
	vs_out.Color = lerp (vs_in.ColorLo, vs_in.ColorHi, vs_in.ColorTime);

	return vs_out;
}
#endif


#ifdef GEOMETRYSHADER
static const float2 Offsets[4] = {float2 (-1, -1), float2 (-1, 1), float2 (1, -1), float2 (1, 1)};

[maxvertexcount(4)]
void ParticleCommonGS (point GS_PARTICLE gs_in[1], inout TriangleStream<PS_PARTICLE> triStream)
{
	for (int i = 0; i < 4; i++)
	{
		PS_PARTICLE gs_out;

		// hack a scale up to keep particles from disapearing
		float2 pscale = Offsets[i] * gs_in[0].HackScale;

		// compute new particle origin
		float3 NewPosition = gs_in[0].Origin + (rightVec * pscale.x + upVec * pscale.y) * particleSize;

		// and finally write it out
		gs_out.Position = mul (WorldMatrix, float4 (NewPosition, 1.0f));
		gs_out.Color = gs_in[0].Color;
		gs_out.Offsets = Offsets[i];

		triStream.Append (gs_out);
	}

	// and finish it
	triStream.RestartStrip ();
}
#endif


#ifdef PIXELSHADER
float4 ParticleSquarePS (PS_PARTICLE ps_in) : SV_TARGET0
{
	return ps_in.Color;
}

float4 ParticleRoundPS (PS_PARTICLE ps_in) : SV_TARGET0
{
	float alpha = min ((1.0f - dot (ps_in.Offsets, ps_in.Offsets)) * 1.5f, 1.0f);
	return float4 (ps_in.Color.rgb, ps_in.Color.a * alpha);
}
#endif

